<template>
    <el-form label-width="auto">
        <el-form-item label="spu名称">
            <el-input placeholder="请输入SPU名称" v-model="spuParams.spuName"></el-input>
        </el-form-item>
        <el-form-item label="spu品牌">
            <!-- select获取tmId后，重新渲染label为tmName -->
            <!-- <el-select placeholder="请选择品牌" v-model="spuParams.tmId">
                <el-option v-for="(item, index) in trademarks" :label="item.tmName" :value="item.id" :key="item.id">
                </el-option>
            </el-select> -->
            <!--  -->
            <!-- 品牌数量多，使用虚拟选择器，提高渲染性能，只生成可见区域的 DOM 元素 -->
            <el-select-v2 v-model="spuParams.tmId" :options="options" placeholder="请选择品牌" />
        </el-form-item>
        <el-form-item label="spu描述">
            <el-input type="textarea" resize="none" placeholder="请输入描述" v-model="spuParams.description"></el-input>
        </el-form-item>
        <!-- 照片墙 -->
        <el-form-item label="spu图片">
            <!-- 注意action上传地址 -->
            <el-upload v-model:file-list="imgList" action="/api/admin/product/fileUpload" list-type="picture-card"
                :on-preview="handlePictureCardPreview" :on-remove="handleRemove" :before-upload="beforeUpload">
                <el-icon>
                    <Plus />
                </el-icon>
            </el-upload>

            <!-- 图片查看器 -->
            <el-image-viewer v-if="showImg" :url-list="previewImgList" :initial-index="currentProviewIndex"
                @close="showImg = false">
            </el-image-viewer>
        </el-form-item>
        <el-form-item label="spu销售属性">
            <!-- 未选择的属性 -->
            <el-select :placeholder="unSelectSaleAttrs.length ? `还有${unSelectSaleAttrs.length}个选择` : '暂无可选'"
                v-model="selectSaleAttr" clearable>
                <el-option v-for="(item, index) in unSelectSaleAttrs" :key="item.id" :label="item.name"
                    :value="`${item.id}:${item.name}`">
                </el-option>
            </el-select>
            <el-button type="primary" icon="Plus" style="margin-left: 10px;" :disabled="!selectSaleAttr"
                @click="addSaleAttr">添加销售属性</el-button>
            <!-- 已选择的属性 -->
            <el-table border style="margin: 10px 0" :data="spuAttrs">
                <el-table-column label="序号" type="index" width="80px" align="center"></el-table-column>
                <el-table-column label="属性名" width="150px" prop="saleAttrName"></el-table-column>
                <el-table-column label="属性值">
                    <template #="{ row, $index }">
                        <!--  @close="deleteAttrValue(row)" -->
                        <el-tag type="success" v-for="(tag, $index) in row.spuSaleAttrValueList" :key="tag.id" closable
                            effect="light" style="margin: 0 10px 10px 0"
                            @close="row.spuSaleAttrValueList.splice($index, 1)">
                            {{ tag.saleAttrValueName }}
                        </el-tag>
                        <!-- input失焦 或 点击回车时添加 -->
                        <el-input :ref="(vc: any) => inputArr[$index] = vc" v-show="$index == inputIndex"
                            placeholder="请输入属性值" @blur="comfirmInput(row)" v-model.trim="inputValue" style="width: 100px"
                            size="small"></el-input>
                        <el-button v-show="$index != inputIndex" @click="showInput($index)" type="primary" size="small"
                            icon="Plus"></el-button>
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="100px">
                    <template #="{ row, $index }">
                        <el-button icon="Delete" size="small" type="danger" @click="spuAttrs.splice($index, 1)"></el-button>
                    </template>
                </el-table-column>
            </el-table>
        </el-form-item>
        <el-form-item>
            <el-button type="primary" @click="onSave">保存</el-button>
            <el-button @click="onCancel">取消</el-button>
        </el-form-item>
    </el-form>
</template>

<script setup lang="ts">
import type { SpuData, SpuImg, SpuAttr, SaleAttr } from '@/api/product/spu/type';
import type { Trademark } from '@/api/product/trademark/type'
import { computed, ref, nextTick } from 'vue'
import { reqAlltrademark, reqSpuImage, reqSpuAttr, reqSaleAttr, reqAddOrUpdateSpu } from '@/api/product/spu/index'
// 图片墙
import { ElMessage, type UploadProps } from 'element-plus'

// 切换场景的函数，子传父
let $emit = defineEmits(['changeSceneSon'])
let emptySpuParams = {
    category3Id: '', //第三级分类id
    spuName: '',     //spu属性名
    description: '', //spu属性介绍
    tmId: undefined,        //品牌id
    spuSaleAttrList: [], //某个spu的全部属性
    spuImageList: []     //某个spu的全部商品图片
}

// 当前添加/编辑的spu数据
let spuParams = ref<SpuData>({ ...emptySpuParams })

// 父组件点击编辑spu按钮，获取当前组件的spu数据
const initSpuData = async (flag: boolean, value: any) => {
    // 将父组件获取的数据解构后，再获取，否则会影响父组件的数据
    if (!flag) {
        spuParams.value = { ...value }
        //spu为父组件传递的不完整的spu数据
        sendRequests(true, value.id as number);
    }
    else spuParams.value.category3Id = value
}

// getAllTrademark接口有问题，品牌过多，请求经常超时，故建议自定义初始数据，便于测试
let trademarks = ref<Trademark[]>([
    { id: 1, tmName: '小米' },
    { id: 2, tmName: '苹果' },
    { id: 3, tmName: '华为' },
    { id: 4, tmName: '尚硅谷' },
    { id: 5, tmName: 'OPPO' },
    { id: 6, tmName: 'VIVO' },
    { id: 7, tmName: '三星' },
    { id: 8, tmName: '长虹' },
    { id: 9, tmName: '索尼' },
])

// 利用Promise异步发送多个请求(flag=true表示修改数据，false表示添加数据)
const sendRequests = (flag: boolean, id: number) => {
    let requests = []
    // 获取所有品牌 / 所有销售属性
    requests.push(reqSaleAttr())
    requests.push(reqAlltrademark())
    if (flag) {
        // 获取spu图片列表，spu属性列表
        requests.push(reqSpuImage(id as number))
        requests.push(reqSpuAttr(id as number))
    }
    Promise.allSettled(requests).then((responses: any) => {
        if (responses[0].status === 'fulfilled')
            allSaleAttrs.value = responses[2].value.data
        if (responses[1].status === 'fulfilled')
            trademarks.value = responses[3].value.data
        if (flag) {
            if (responses[2].status === 'fulfilled')
                // 照片墙数据，参数名必须为name和url
                imgList.value = responses[0].value.data.map((item: SpuImg) => {
                    return {
                        name: item.imgName,
                        url: item.imgUrl
                    }
                })
            if (responses[3].status === 'fulfilled')
                spuAttrs.value = responses[1].value.data
        }
    }).catch((error: Error) => {
        console.log(error)
    })
}

// 显示所有spu品牌的虚拟选择器select的选项
let options = computed(() => {
    return trademarks.value.map(item => {
        return {
            value: item.id,
            label: item.tmName
        }
    })
})

// 照片墙的图片列表
let imgList = ref<SpuImg[]>([])
// 图片预览
let showImg = ref<boolean>(false)
// 图片预览列表
let previewImgList = ref<(string | undefined)[]>()
// 当前预览图片的索引
let currentProviewIndex = ref<number>(0)

// 照片墙移除图片
const handleRemove: UploadProps['onRemove'] = (uploadFile, uploadFiles) => {
    console.log(uploadFile, uploadFiles)
}

// 照片墙预览照片（设置el-image-viewer）
const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
    previewImgList.value = imgList.value.map(item => item.url);
    showImg.value = true
    currentProviewIndex.value = imgList.value.findIndex(item => (item.url == uploadFile.url));
}

// 照片墙限制上传文件类型和大小
const beforeUpload: UploadProps['beforeUpload'] = (rawFile) => {
    // 限制文件类型和大小：png jpg gif 2M
    let imgType = ['image/jpeg', 'image/png', 'image/gif'];
    // 文件类型不匹配
    if (!imgType.includes(rawFile.type)) {
        ElMessage.error('上传文件格式为 PNG/JPG/GIF')
        return false
    }
    // 文件大小超过1M
    else if (rawFile.size / 1024 / 1024 > 1) {
        ElMessage.error('图片大小不能超过 2MB')
        return false
    }
    return true
}

// 当前spu的属性值
let spuAttrs = ref<SpuAttr[]>([])
// 所有销售属性值
let allSaleAttrs = ref<SaleAttr[]>([
    { id: 1, name: '颜色' },
    { id: 2, name: '版本' },
    { id: 3, name: '尺码' }
])
// 选择添加的销售属性
let selectSaleAttr = ref<string>('')

// 可选择添加的销售属性（computed动态计算）
let unSelectSaleAttrs = computed(() => {
    // 获取已有的销售属性的集合
    let exsitList = new Set(spuAttrs.value.map(item => item.saleAttrName));
    // 在全部销售属性中，去除已有的
    let result = allSaleAttrs.value.filter(item => !exsitList.has(item.name));
    return result
})

// 添加销售属性
const addSaleAttr = () => {
    let [baseSaleAttrId, saleAttrName] = selectSaleAttr.value?.split(':');
    let newSaleAttr = {
        baseSaleAttrId: Number(baseSaleAttrId),
        saleAttrName,
        spuSaleAttrValueList: []
    }
    spuAttrs.value.push(newSaleAttr)
    selectSaleAttr.value = ''
}

// 属性值input的实例
let inputArr = ref<any>([])
// 当前显示input的索引
let inputIndex = ref<number>(-1)
// 当前input值
let inputValue = ref<string>('')
// 显示所点击行的input框，并聚焦
const showInput = (index: number) => {
    inputIndex.value = index
    inputValue.value = ''
    nextTick(() => {
        inputArr.value[index].input.focus()
    })
}
// input失焦或点击回车时，保存属性值，清空input框的值（值为空则不添加）
const comfirmInput = (row: SpuAttr) => {
    inputIndex.value = -1
    if (inputValue.value)
        row.spuSaleAttrValueList.push({
            baseSaleAttrId: row.baseSaleAttrId as number,
            saleAttrValueName: inputValue.value
        })
}

// 点击“取消”，清空数据，返回父组件
const onCancel = (reset = false) => {
    spuParams.value = { ...emptySpuParams };
    imgList.value = []
    spuAttrs.value = []
    selectSaleAttr.value = ''
    nextTick(() => {
        $emit('changeSceneSon', reset)
    })
}

// 点击“保存”，
const onSave = async () => {
    // 获取照片墙数据
    spuParams.value.spuImageList = imgList.value.map((item: any) => {
        return {
            imgName: item.name,
            imgUrl: (item.response && item.response.data) || item.url
        }
    })

    // 获取销售属性
    spuParams.value.spuSaleAttrList = spuAttrs.value

    // 发送请求
    let result = await reqAddOrUpdateSpu(spuParams.value)
    if (result.code == 200) {
        ElMessage.success(spuParams.value.id ? '修改成功' : '添加成功')
        onCancel(true);
    }
    else {
        ElMessage.error(spuParams.value.id ? '修改失败' : '添加失败')
    }
}

// 对外暴露子组件方法
defineExpose({ initSpuData })
</script>

<style scoped></style>